---
title: Gestures
section: Reference
order: 1
---

import UseGesture from './code/rug'
import { CodeSnippet, TabPanel } from './CodeSnippet'

# Available gestures

&zwnj;<UseGesture /> exists in two packages, one for React and one for Vanilla&nbsp;JS (which is new from v10).

<carbon-ad />

## React

&zwnj;<UseGesture pkg="react" /> exports several hooks that can handle different gestures.

| Hook         | Description                                |
| ------------ | ------------------------------------------ |
| `useDrag`    | Handles the drag gesture                   |
| `useMove`    | Handles mouse move events                  |
| `useHover`   | Handles mouse enter and mouse leave events |
| `useScroll`  | Handles scroll events                      |
| `useWheel`   | Handles wheel events                       |
| `usePinch`   | Handles the pinch gesture                  |
| `useGesture` | Handles multiple gestures in one hook      |

### Usage

With the exception of `useGesture` which is a special hook, all other hooks share the same API:

```jsx
const bind = useDrag((state) => doSomethingWith(state), config)
return <div {...bind(arg)} />
```

- `state` is an object containing all attributes of the gesture, including the original event. That state is passed to your handler every time the gesture updates. You can find all state attributes in the [Gesture state section](/docs/state).
- `config` is an object containing options for the gesture. You can find all config options in the [Gesture options section](/docs/options).
- `arg` is a custom argument you can pass to the bind function. See this [example](https://codesandbox.io/s/github/pmndrs/use-gesture/tree/main/demo/src/sandboxes/draggable-list) to see where it can be useful.

## Vanilla

&zwnj;<UseGesture pkg="vanilla" /> exports several classes that can handle different gestures.

| Hook            | Description                                |
| --------------- | ------------------------------------------ |
| `DragGesture`   | Handles the drag gesture                   |
| `MoveGesture`   | Handles mouse move events                  |
| `HoverGesture`  | Handles mouse enter and mouse leave events |
| `ScrollGesture` | Handles scroll events                      |
| `WheelGesture`  | Handles wheel events                       |
| `PinchGesture`  | Handles the pinch gesture                  |
| `Gesture`       | Handles multiple gestures in one hook      |

### Usage

With the exception of `Gesture` which is a special hook, all other hooks share the same API:

```html
<!-- index.html -->
<div id="drag" />
```

```js
// script.js
const el = document.getElementById('drag')
const gesture = new DragGesture(el, (state) => doSomethingWithState(state), config)
```

- `state` is an object containing all attributes of the gesture, including the original event. That state is passed to your handler every time the gesture updates. You can find all state attributes in the [Gesture state section](/docs/state).
- `config` is an object containing options for the gesture. You can find all config options in the [Gesture options section](/docs/options).

## Some notes

### About the drag gesture

The drag gesture is possibly the most popular gesture of <UseGesture />. Because of the way pointer events work, dragging might cause conflict with scrolling on touch-based devices. So to signify that your element is draggable and therefore shouldn't trigger the browser scrolling, you **need** to use the [`touch-action`](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action) css property. [Read more here](/docs/extras/#touch-action).

### About the pinch gesture

The pinch gesture is a bit specific because depending on your device input, it might behave differently. On touch devices, two pointers (generally your fingers) allow for zooming and rotating.

But Macbook trackpads also support pinching and rotating in Safari. To make sure the zooming gesture doesn't interfere with Safari accessibility zoom, you will need to prevent the gesture like so:

```js
document.addEventListener('gesturestart', (e) => e.preventDefault())
document.addEventListener('gesturechange', (e) => e.preventDefault())
```

> Because React doesn't support proprietary Webkit GestureEvents, you will need to attach the gesture using a ref, with the `target` [option](/docs/options/#target).

Also, a pretty unknown feature allows devices supporting wheel to **zoom** (not rotate) by wheeling and pressing the **control** modifier key. <UseGesture pkg="react" /> supports it, but to make sure the zooming doesn't interefere with the browser accessibility zoom, you'll also be better using the `target` [option](/docs/options/#target).

### About the wheel gesture

The wheel gesture is a bit tricky, due to the nature of the wheel event. In fact, mouse devices such as the Macbook trackpad, or the Magic Mouse have inertia, but there is no native way to distinguish between an actual wheel intent and its resulting inertia. To detect intent, you can use [Lethargy](https://github.com/d4nyll/lethargy) and [read more about it here](/docs/extras/#lethargy).

## Handling multiple gestures at once

### useGesture and Gesture

&zwnj;<UseGesture /> also allows you to manage different gestures at the same time: for example you might want to enable pinching and dragging on the same component, in that case this is the way to go.

<CodeSnippet>
  <TabPanel>

```jsx
import { useGesture } from '@use-gesture/react'

const bind = useGesture(
  {
    onDrag: (state) => doSomethingWith(state),
    onDragStart: (state) => doSomethingWith(state),
    onDragEnd: (state) => doSomethingWith(state),
    onPinch: (state) => doSomethingWith(state),
    onPinchStart: (state) => doSomethingWith(state),
    onPinchEnd: (state) => doSomethingWith(state),
    onScroll: (state) => doSomethingWith(state),
    onScrollStart: (state) => doSomethingWith(state),
    onScrollEnd: (state) => doSomethingWith(state),
    onMove: (state) => doSomethingWith(state),
    onMoveStart: (state) => doSomethingWith(state),
    onMoveEnd: (state) => doSomethingWith(state),
    onWheel: (state) => doSomethingWith(state),
    onWheelStart: (state) => doSomethingWith(state),
    onWheelEnd: (state) => doSomethingWith(state),
    onHover: (state) => doSomethingWith(state)
  },
  config
)

return <div {...bind()} />
```

The `config` object passed to `useGesture` has `drag`, `wheel`, `scroll`, `pinch` and `move` keys for specific gesture options. [See here for more details](/docs/options/#structure-of-the-config-object).

</TabPanel>
<TabPanel>

```js
import { Gesture } from '@use-gesture/vanilla'

const gesture = new Gesture(
  element,
  {
    onDrag: (state) => doSomethingWith(state),
    onDragStart: (state) => doSomethingWith(state),
    onDragEnd: (state) => doSomethingWith(state),
    onPinch: (state) => doSomethingWith(state),
    onPinchStart: (state) => doSomethingWith(state),
    onPinchEnd: (state) => doSomethingWith(state),
    onScroll: (state) => doSomethingWith(state),
    onScrollStart: (state) => doSomethingWith(state),
    onScrollEnd: (state) => doSomethingWith(state),
    onMove: (state) => doSomethingWith(state),
    onMoveStart: (state) => doSomethingWith(state),
    onMoveEnd: (state) => doSomethingWith(state),
    onWheel: (state) => doSomethingWith(state),
    onWheelStart: (state) => doSomethingWith(state),
    onWheelEnd: (state) => doSomethingWith(state),
    onHover: (state) => doSomethingWith(state)
  },
  config
)
```

The `config` object passed to `Gesture` has `drag`, `wheel`, `scroll`, `pinch` and `move` keys for specific gesture options. [See here for more details](/docs/options/#structure-of-the-config-object).

</TabPanel>
</CodeSnippet>

### Start and end handlers

As you can see from the snippet above, the `useGesture` hook allows `drag`, `wheel`, `scroll`, `pinch` and `move` gestures to have two additional handlers that let you perform actions when they start or end. For example, `onScrollEnd` fires when the user just finished scrolling.

Note that **end event handlers** for `wheel`, `scroll` and `move` are **debounced** because of the way these events work in the DOM.

### Native event handlers in React

Imagine you want to add an action when you mouse down on a draggable component. You'll probably be tempted to try the following code at first:

```jsx highlight={1,4-5}
// This won't work as you'd expect
function DragAndPointerDown() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ down, offset: [x, y] }) => api.start({ x, y }))
  return <animated.div {...bind()} onPointerDown={() => console.log('pointer down')} style={{ x, y }} />
}
```

This looks fine on paper, but it actually won't work: the reason is that the attribute `onPointerDown` will overwrite the one created by expanding `{...bind()}` and therefore the drag gesture won't start.

Fortunately, the hook `useGesture` supports native React event handlers, and will make sure they are executed on the side without overwriting anything:

```jsx highlight={1,4-8}
// This will work as intended
function DragAndPointerDown() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useGesture({
    onDrag: ({ down, offset: [x, y] }) => api.start({ x, y }),
    onPointerDown: ({ event, ...sharedState }) => console.log('pointer down', event)
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

Even better, the native handler will be passed the shared state of the gestures, including the original event, and the arguments passed to the `bind` function.

### Better tree shaking with createUseGesture and createGesture

<CodeSnippet>
  <TabPanel>

The `useGesture` hook conveniently offers all gestures out of the box. This comes at the expense of one or two kb of extra gzipped javascript.

If you'd like to only import the code for the gestures you need, you can create a custom `useGesture` hook like so:

```jsx
import { createUseGesture, dragAction, pinchAction } from '@use-gesture/react'

const useGesture = createUseGesture([dragAction, pinchAction])

const bind = useGesture(
  {
    onDrag: (state) => doSomethingWith(state),
    onDragStart: (state) => doSomethingWith(state),
    onDragEnd: (state) => doSomethingWith(state),
    onPinch: (state) => doSomethingWith(state),
    onPinchStart: (state) => doSomethingWith(state),
    onPinchEnd: (state) => doSomethingWith(state)
  },
  { drag: dragConfig, pinch: pinchConfig }
)

return <div {...bind()} />
```

</TabPanel>
<TabPanel>

`Gesture` conveniently offers all gestures out of the box. This comes at the expense of one or two kb of extra gzipped javascript.

If you'd like to only import the code for the gestures you need, you can create a custom `Gesture` recognizer like so:

```js
import { createGesture, dragAction, pinchAction } from '@use-gesture/vanilla'

const Gesture = createGesture([dragAction, pinchAction])

const gesture = new Gesture(
  element,
  {
    onDrag: (state) => doSomethingWith(state),
    onDragStart: (state) => doSomethingWith(state),
    onDragEnd: (state) => doSomethingWith(state),
    onPinch: (state) => doSomethingWith(state),
    onPinchStart: (state) => doSomethingWith(state),
    onPinchEnd: (state) => doSomethingWith(state)
  },
  { drag: dragConfig, pinch: pinchConfig }
)
```

</TabPanel>
</CodeSnippet>

Available actions are:

- `dragAction`
- `hoverAction`
- `moveAction`
- `pinchAction`
- `scrollAction`
- `wheelAction`
